/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.openbookformat.project;

import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.text.BadLocationException;
import javax.swing.text.StyledDocument;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectInformation;
import org.netbeans.spi.project.ActionProvider;
import org.netbeans.spi.project.ProjectState;
import org.netbeans.spi.project.ui.support.DefaultProjectOperations;
import org.openide.cookies.EditorCookie;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.util.Exceptions;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;

/**
 *
 * @author MUFEED
 */
public class OBFProject implements Project {
    public static final int CHAPTERS_CHANGED = 1;
    public static final int HEADINGS_CHANGED = 2;

    private final FileObject projectDir;
    private final ProjectState state;
    private Lookup lookup;
    private InstanceContent contents = new InstanceContent();
    private boolean modified = false;
    private int whatModified = -1;
    private final BookProp bookProp;
    
    public OBFProject(FileObject projectDir, ProjectState state) {
        this.projectDir = projectDir;
        this.state = state;
        this.bookProp = new BookProp(this);
        bookProp.getLookup().lookup(Observable.class).addObserver(new Observer() {
            @Override
            public void update(Observable o, Object obj) {
                List array = (List) obj;
                System.out.println(array.get(0));
                if(!array.isEmpty() && array.get(0) instanceof Chapter) {
                    whatModified = CHAPTERS_CHANGED;
                } else if(!array.isEmpty() && array.get(0) instanceof HeadingPointer) {
                    whatModified = HEADINGS_CHANGED;
                }
                setModified(true); 
            }
        });
    }

    FileObject getProjectFile(boolean create) {
        FileObject result =
                projectDir.getFileObject(OBFProjectFactory.PROJECT_FILE);
        if (result == null && create) {
            try {
                result = projectDir.createFolder(OBFProjectFactory.PROJECT_FILE);
            } catch (IOException ioe) {
                Exceptions.printStackTrace(ioe);
            }
        }
        return result;
    }

    @Override
    public FileObject getProjectDirectory() {
        return projectDir;
    }

    @Override
    public Lookup getLookup() {
        if(lookup == null) {
            lookup = new AbstractLookup(contents);

            contents.add(state);
            contents.add(new ActionProviderImpl());
            contents.add(new Info());
            contents.add(new OBFProjectLogicalView(this));
            contents.add(bookProp);
        }

        return lookup;
    }

    public boolean isModified() {
        return modified;
    }

    protected void setModified(boolean modified) {
        System.out.println("Mod:" + modified);
        this.modified = modified;

        if(modified) {
            try {
                switch(whatModified) {
                    case CHAPTERS_CHANGED:
                        saveProjectFile();
                        break;
                    case HEADINGS_CHANGED:
                        saveHeadingFile();
                        break;
                    default:
                }
            } catch (BadLocationException ex) {
                Exceptions.printStackTrace(ex);
            } catch (DataObjectNotFoundException ex) {
                Exceptions.printStackTrace(ex);
            } catch (IOException ex) {
                Exceptions.printStackTrace(ex);
            }

            setModified(false);
        }
    }

    private void saveProjectFile() throws DataObjectNotFoundException, IOException, BadLocationException {
        DataObject dObj = DataObject.find(getProjectFile(true));
        EditorCookie ed = dObj.getCookie(EditorCookie.class);

        if (ed != null) {
            StyledDocument doc = ed.openDocument();
            doc.remove(0, doc.getLength());

            //construct XML file
            StringBuilder buff = new StringBuilder();
            buff.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
            buff.append("<project-prop>\n");
            //appending chapters
            buff.append("    <chapters>\n");
            for (int i = 0; i < bookProp.getTotalNumberOfChapter(); i++) {
                buff.append("        <chapter>").append(bookProp.getChapter(i).getTitle()).append("</chapter>\n");
            }
            buff.append("    </chapters>\n");
            buff.append("</project-prop>\n");

            doc.insertString(0, buff.toString(), null);

            dObj.setModified(true);
        }
    }

    private void saveHeadingFile() throws DataObjectNotFoundException, IOException, BadLocationException {
        DataObject dObj = DataObject.find(getProjectDirectory().getFileObject(
                    OBFProjectFactory.HEADING_FILE));
        EditorCookie ed = dObj.getCookie(EditorCookie.class);

        if (ed != null) {
            StyledDocument doc = ed.openDocument();
            doc.remove(0, doc.getLength());

            //construct Properties file
            StringBuilder buff = new StringBuilder();
            buff.append("heading_count=").append(bookProp.getHeadings().size()).append("\n\n");
            String ptrIdx = null;
            //appending headings
            for (int i = 0; i < bookProp.getTotalNumberOfHeadings(); i++) {
                //ptrIdx = ((i+1)<99?"0":"") + ((i+1)<9?"0":"") + i;
                ptrIdx = (i < 100?"0":"") + (i < 10?"0":"") + i;
                buff.append("idx_").append(ptrIdx).append("_chapter=").append(
                        bookProp.getHeadingPointer(i).getChapter().getTitle()).append("\n");
                buff.append("idx_").append(ptrIdx).append("_offset=").append(
                        bookProp.getHeadingPointer(i).getOffset()).append("\n");
                buff.append("idx_").append(ptrIdx).append("_level=").append(
                        bookProp.getHeadingPointer(i).getLevel()).append("\n");
                buff.append("idx_").append(ptrIdx).append("_heading=").append(
                        bookProp.getHeadingPointer(i).getHeading()).append("\n");
                buff.append("\n");
            }

            doc.insertString(0, buff.toString(), null);

            dObj.setModified(true);
        }
    }

    private final class ActionProviderImpl implements ActionProvider {


        @Override
        public String[] getSupportedActions() {
            return new String[]{
              ActionProvider.COMMAND_DELETE,
              ActionProvider.COMMAND_COPY,
            };
        }

        @Override
        public void invokeAction(String command, Lookup lookup) throws IllegalArgumentException {
            if(command.equals(ActionProvider.COMMAND_DELETE)) {
                DefaultProjectOperations.performDefaultDeleteOperation(OBFProject.this);
            }

            if(command.equals(ActionProvider.COMMAND_COPY)) {
                DefaultProjectOperations.performDefaultCopyOperation(OBFProject.this);
            }
        }

        @Override
        public boolean isActionEnabled(String command, Lookup lookup) throws IllegalArgumentException {
            if(command.equals(ActionProvider.COMMAND_DELETE) ||
                    command.equals(ActionProvider.COMMAND_COPY)) {
                return true;
            }
            throw new IllegalArgumentException(command);
        }
    }

    public final class Info implements ProjectInformation {

        @Override
        public String getName() {
            return getProjectDirectory().getName();
        }

        @Override
        public String getDisplayName() {
            return getName();
        }

        @Override
        public Icon getIcon() {
            return new ImageIcon(ImageUtilities.loadImage(
                    "org/openbookformat/project/library.png"));
        }

        @Override
        public Project getProject() {
            return OBFProject.this;
        }

        @Override
        public void addPropertyChangeListener(PropertyChangeListener pl) {}

        @Override
        public void removePropertyChangeListener(PropertyChangeListener pl) {}

    }

}
